package cn.android666.nopreviewcamera

import android.graphics.Bitmap
import android.graphics.ImageFormat
import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.os.Bundle
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.createBitmap
import androidx.core.view.isNotEmpty
import cn.android666.nopreviewcamera.databinding.ActivityMainBinding
import org.doubango.jni.Libyuv
import org.opencv.android.OpenCVLoader
import org.opencv.android.Utils
import org.opencv.core.Mat
import timber.log.Timber
import java.text.SimpleDateFormat
import java.util.concurrent.Executors
import kotlin.concurrent.thread

class MainActivity : AppCompatActivity() {

    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
    private var camera: Camera? = null
    private val surfaceTexture = SurfaceTexture(0)
    private val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    private val pool = Executors.newSingleThreadExecutor()
    private var h264EncoderThread: H264EncoderThread? = null
    private lateinit var nv12Bytes: ByteArray

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        binding.startPreview.setOnClickListener { startPreview() }
        binding.stopPreview.setOnClickListener { stopPreview() }
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            Timber.i("是否有Camera权限：$it")
            if (it) {
                startPreview()
            }
        }.launch(android.Manifest.permission.CAMERA)

        if (OpenCVLoader.initLocal()) {
            Timber.i("OpenCV本地库加载成功")
        } else {
            Timber.i("OpenCV初始化失败")
        }

        val am = getSystemService(ACTIVITY_SERVICE) as android.app.ActivityManager
        // 应用程序使用的GlEs版本。上16位表示主版本，下16位表示次版本。GlEs是OpenGL for Embedded Systems（OpenGL ES）的缩写
        // 0x00010000 表示 OpenGL ES 1.0
        // 0x00020000 表示 OpenGL ES 2.0
        // 0x00030000 表示 OpenGL ES 3.0
        val glEsVersion = am.deviceConfigurationInfo.reqGlEsVersion
        val isGlEs1Supported = glEsVersion >= 0x10000 // 判断是否支持OpenGL ES 1.0
        Timber.i("isGlEs1Supported: $isGlEs1Supported")
        val isGlEs2Supported = glEsVersion >= 0x20000 // 判断是否支持OpenGL ES 2.0
        Timber.i("isGlEs2Supported: $isGlEs2Supported")
        val isGlEs3Supported = glEsVersion >= 0x30000 // 判断是否支持OpenGL ES 3.0
        Timber.i("isGlEs3Supported: $isGlEs3Supported")

    }

    private fun showMatInImageView(mat: Mat) {
        val bitmap = createBitmap(mat.cols(), mat.rows(), Bitmap.Config.RGB_565)
        Utils.matToBitmap(mat, bitmap)
//        binding.previewContainer.removeAllViews()
        val imageView = ImageView(this)
//        binding.previewContainer.addView(imageView)
        imageView.setImageBitmap(bitmap)
    }

    private fun startPreview() {
        // 如果相机已经打开，先释放
        camera?.release()
        val camera = Camera.open() ?: return
        this.camera = camera
        try {
            /*val previewWidth = 1920
            val previewHeight = 1080*/

            val previewWidth = 640
            val previewHeight = 480

            /*val previewWidth = 176
            val previewHeight = 144*/

            //YUVWatermarkUtils.init(previewWidth, previewHeight)
            //nv12Bytes = ByteArray(previewWidth * previewHeight * 3 / 2)

            // 设置相机参数
            camera.apply {
                parameters = parameters?.apply {
                    previewFormat = ImageFormat.NV21
                    setPreviewSize(previewWidth, previewHeight)
                    supportedPreviewSizes.forEach { Timber.i("supportedPreviewSizes: ${it.width}x${it.height}") }
                }
            }

            val info = Camera.CameraInfo()
            Camera.getCameraInfo(0, info)
            binding.yuvGLSurfaceView.setCameraRotation(info.orientation)
            Timber.e("---------------------${info.orientation}------------------------")

            camera.setPreviewCallback(object : Camera.PreviewCallback {
                override fun onPreviewFrame(data: ByteArray, camera: Camera) {
                    //h264EncoderThread?.addYUVDatas(data)

                    //val nv12BytesTemp = nv12Bytes
                    pool.execute {
                        //val start = System.currentTimeMillis()
                        //Libyuv.NV21ToNV12(data, nv12BytesTemp, previewWidth, previewHeight) // 当转换1080P时，经常需要10ms以上，有个别帧需要20多ms
                        //Timber.i("nv21ToNV12耗时：${System.currentTimeMillis() - start}ms")
                        //h264EncoderThread?.addYUVDatas(nv12BytesTemp)

                        val updateYuvDataStart = System.currentTimeMillis()
                        binding.yuvGLSurfaceView.updateYuvData(data, previewWidth, previewHeight)
                        Timber.i("${Thread.currentThread().name}, updateYuvData useTime = ${System.currentTimeMillis()  - updateYuvDataStart}")
                    }

                    //nv12Bytes = data
                }
            })

            // 不设置预览容器，则可以实现无预览录像
            //camera.setPreviewDisplay(surfaceHolder)
            camera.setPreviewTexture(surfaceTexture) // 有些手机不支持无预览录像，则可以设置一个虚拟的预览容器，打开这个注释即可。

            thread {
                // H264EncoderThread创建需要200 ~ 300ms，所以这里创建一个线程，避免阻塞UI线程
                //val start = System.currentTimeMillis()
                //h264EncoderThread = H264EncoderThread(previewWidth, previewHeight).also { it.start() }
                //Timber.i("创建H264EncoderThread耗时：${System.currentTimeMillis() - start}ms")
                runOnUiThread {
                    // 编码器准备好之后再开始预览
                    camera.startPreview()
                    Toast.makeText(this, "预览已开始", Toast.LENGTH_SHORT).show()
                }
            }

        } catch (e: Exception) {
            e.printStackTrace()
            Toast.makeText(this, "无法开始预览: ${e.message}", Toast.LENGTH_SHORT).show()
        }
    }

    private fun stopPreview() {
        try {
            camera?.let {
                it.setPreviewCallback(null)
                it.stopPreview()
                it.release()
                camera = null
            }
            h264EncoderThread?.close()
            h264EncoderThread = null
            Toast.makeText(this, "预览已停止", Toast.LENGTH_SHORT).show()
        } catch (e: Exception) {
            e.printStackTrace()
            Toast.makeText(this, "停止预览时出错: ${e.message}", Toast.LENGTH_SHORT).show()
        }
    }
}